/************************************************

     Brian Bousquet-Smith     Chaz Godwin
	            
		    OBDII Reader
	             Fall 2011
************************************************/

#include <avr/io.h>
#include <avr/iom164.h> 
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


/************************************************
		     Defines
************************************************/

// States


#define OK 		0
#define ELM_INIT_STATE	1
#define LCD_INIT_STATE	2
#define	OBD_INIT_STATE	3
#define DASHBOARD	4
#define PERFORMANCE	5
#define DIAGNOSTICS	6
#define ABOUT		7

// ELM Defines

#define COMMAND_END		0x0D

// OBD Defines

#define RESPONSE_END		0x3E



/************************************************
		Function Prototypes
************************************************/

// Initializing Functions

void power_on();
void serial_init();
int elm_init();
int obd_init();
int get_mph();

// Tx Rx Functions

void lcd_transmit(unsigned char data);
void obd_transmit(unsigned char data);
unsigned char lcd_receive();
unsigned char obd_receive();


/************************************************
		Global Variables
************************************************/

int state = ELM_INIT_STATE;
int timeoutflag = 0;

/************************************************
		Main Code
************************************************/




int main(void){

/*
*	Purpose: Output RPM and MPH data from a vehicle
*/
	power_on();
	serial_init();
	int response;
	_delay_ms(5000);
	while(1){
		PORTA = state;
		switch(state){
		case ELM_INIT_STATE: // Initializes ELM
			response = elm_init();
			if(response == OK){
				state = OBD_INIT_STATE;
				break;
			}
			else{
				PORTA = 0x0F;
				break; 
			}

		case LCD_INIT_STATE: // Initializes LCD
			//response = lcd_init();
			if(response == OK){
				state = OBD_INIT_STATE;
				break;
			}
			else break;
	
		case OBD_INIT_STATE: // Initializes OBDII
			response = obd_init();
			if(response == OK){
				state = DASHBOARD;
				break;
			}
			else{
				PORTA = 0x07; 
				break;
			}

		case DASHBOARD: // Virtual Dashboard
			response = get_mph();
			_delay_ms(50);
			response = get_rpm();
			_delay_ms(50);
			break;
		
		case PERFORMANCE:
			break;		
		
		case DIAGNOSTICS:
			break;
		
		case ABOUT:
			break; 
	}
	return 0;
}

void power_on(){

/*
*	Purpose: Turn the power light on of the device
*	Input: Nothing
*	Output: Nothing
*/

	DDRA=0xFF;
	PORTA = 0x0F;

}

void serial_init(){

/*
*	Purpose: Initialize Serial on Both UART Ports on the AVR
*	Input: Nothing
*	Output: Nothing
*/

	UCSR0A |= (1<<U2X0);			// Double speed for more precision
	UCSR0B |= (1<<RXEN0)|(1<<TXEN0);	// Allow transmit and receive
	UCSR0C |= (0<<USBS0)|(3<<UCSZ00); 	// 8 Bit No Parity 1 Stop Bit
	UBRR0H = 0;				// Sets Baud Rate = 9600
	UBRR0L = 12;

	UCSR1A |= (1<<U2X1);			// Double speed for more precision
	UCSR1B |= (1<<RXEN1)|(1<<TXEN1); 	// Allow transmit and receive
	UCSR1C |= (1<<USBS1)|(3<<UCSZ10); 	// 8 Bit 2 Stop Bits
	UBRR1H = 0;				// Sets Baud Rate = 9600
	UBRR1L = 12;
}

int elm_init(){

/*
*	Purpose: Initialize ELM and check that communication is correct
*	Input: Nothing
*	Output:	Error Codes:
*		0 -	Successful
*		-1 - 	Unsuccessful
*/

	unsigned char init_buffer[3] = {'A', 'T', 'Z'};
	int i;
	unsigned char echo;
	unsigned char response;
	unsigned char elm_buffer[12] = {		
			'E', 
			'L', 
			'M', 
			'3', 
			'2', 
			'7', 
			' ', 
			'v', 
			'1', 
			'.', 
			'4', 
			'b'};
	
	unsigned char elm_response[20];

	// Send ELM the Initialize Command	

	PORTA = 0x07;
	//for(i=0;i<3;i++){
	//	obd_transmit(init_buffer[i]); 
	//	echo = obd_receive();	
	//	if(echo != init_buffer[i]) return -1;
	//}
	obd_transmit('A');
	obd_transmit('T');
	obd_transmit('Z');
	obd_transmit(0x0D);
	
	/* At this point OBD should respond with the following
		ELM327 v1.4b
	   And lights should flash on the LED connected to the ELM
	*/
	int count =0;
	while( (response = obd_receive()) != 'E') lcd_transmit(response);
	elm_response[count] = response;
	lcd_transmit(response);
	count++;
	while( (response = obd_receive()) != 0x3E){
		elm_response[count] = response;		
		lcd_transmit(response);
		count++;
	}
	for(i=0;i<12;i++){
		if(elm_response[i] != elm_buffer[i]){
			lcd_transmit(i+42);
			return -1;
		}
	}
	return 0;
	
}
	
int obd_init(){

/*
*	Purpose: Initialize OBDII port and check that communication is correct
*	Input: Nothing
*	Output: Error Codes:
*		0 -	Successful
*		-1 - 	Unsuccessful
*/
	
	unsigned char init_buffer[4] = {'0', '1', '0', '0'};
	int i;
	int flag;
	unsigned char echo;
	unsigned char response;
	
	// Figure out if OBD has valid protocol/is connected
	
	for(i=0;i<4;i++){
		obd_transmit(init_buffer[i]);
		echo = obd_receive();
		if (echo != init_buffer[i]) return -1;
	}
	obd_transmit(COMMAND_END);
	
	/* At this point OBD should response with 
		Searching...
	   	If nothing found outputs
			Unable to Connect
		If found protocol
			41 00 + 4 Bytes of Data 
	*/
	flag = 0;
	while( (response = obd_receive()) != RESPONSE_END){
		if(response == 'U') flag = -1;		
		lcd_transmit(response);
	}
	return flag;

}

int get_mph (void){

/*
*	Purpose: Get MPH Data and Output It
*	Input: Nothing
*	Output: Error Codes:
*		0 - Successful
*		-1 - Unsuccessful
*/

	unsigned char mph_buffer[4] = {'0', '1', '0', 'D'};
	unsigned char mph_output[7] = {'M', 'P', 'H', ':', 0, 0, 0};	
	unsigned char echo;
	unsigned char response;
	int i;
	
	for(i=0;i<4;i++){
		obd_transmit(mph_buffer[i]);
		echo = obd_receive();
		if (echo != mph_buffer[i]) return -1;
	}		
	
	while( (response = obd_receive()) != RESPONSE_END){
		lcd_transmit(response);
	}
	return 0;
} 	

int get_rpm(void){

/*
*	Purpose: Get RPM Data and Output it
*	Input: Nothing
*	Output: Error Codes:
*		0 - Successful
*		-1 - Unsuccessful
*/

	unsigned char rpm_buffer[4] = {'0', '1', '0', 'C'};
	unsigned char rpm_output[9] = {'R', 'P', 'M', ':', 0, 0, 0, 0, 0};
	unsigned char echo;
	unsigned char response;
	int i;
	
	for(i=0;i<4;i++){
		obd_transmit(rpm_buffer[i]);
		echo = obd_receive();
		if (echo != rpm_buffer[i]) return -1;
	}
	
	while( (response = obd_receive()) != RESPONSE_END){
		lcd_transmit(response);
	}
}

void lcd_transmit (unsigned char data){
	
/*
*	Purpose: Transmit data to the LCD
*	Input: Data to be transmitted
*	Output:	Nothing
*/
	while( !(UCSR1A & (1<<UDRE1)));
	UDR1 = data;
}

unsigned char lcd_receive (void){

/*
*	Purpose: Receive data from the LCD
*	Input: Nothing
*	Output:	Data received	
*/

	while (!(UCSR1A & (1<<RXC1)));
	return UDR1;
}	

void obd_transmit (unsigned char data){

/*
*	Purpose: Transmit data to the LCD
*	Input: Data to be transmitted
*	Output:	Nothing
*/

	while( !(UCSR0A & (1<<UDRE0)));
	UDR0 = data;
}

unsigned char obd_receive (void){

/*
*	Purpose: Receive data from the LCD
*	Input: Nothing
*	Output:	Data received	
*/
	data
	while (!(UCSR0A & (1<<RXC0))) {
		
	return UDR0;
}



 
